
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Random;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.Sprite;

public class Game extends GameCanvas implements CommandListener {

    private final int X = 1;
    private final int O = 2;
    private final int areay = getGraphics().getFont().getHeight() * 2 + 1;
    private final int areax = 2;
    private final int areaw = 120;
    private final int areah = 120;
    private int celulaw = 40;
    private int celulah = 40;
    private DataInputStream entrada;
    private DataOutputStream saida;
    private int play;
    private String meunome;
    private int[] campos = new int[9];
    int camposselecionado = 0;
    private Sprite lapis;
    private boolean jogada = false;
    private int pp1 = 0;
    private int pp2 = 0;
    private String nomedele;
    private Command cmdMarcar;

    Game(InputStream in, OutputStream out, int play, String nome) {
        super(false);
        this.entrada = new DataInputStream(in);
        this.saida = new DataOutputStream(out);
        this.play = play;
        this.meunome = nome;

        try {
            this.saida.writeUTF(this.meunome);
            this.saida.flush();

            this.nomedele = this.entrada.readUTF();

            int come = 0;

            if (play == 1) {
                come = new Random(System.currentTimeMillis()).nextInt(2) + 1;
                this.saida.writeInt(come);
                this.saida.flush();
            } else {
                come = this.entrada.readInt();
            }

            this.lapis = new Sprite(Image.createImage("/lapis.png"));
            this.lapis.setVisible(come == play);
            this.jogada = (come == play);
            this.cmdMarcar = new Command("Marcar", Command.OK, 0);
            this.addCommand(cmdMarcar);
            this.setCommandListener(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void start() {
        posLapis();
        renderStatus();
        renderArea();
        flushGraphics();
        stWait();
    }

    private void renderStatus() {
        Graphics g = getGraphics();

        if (this.play == 1) {
            g.setColor(65360);
            g.drawString(this.meunome + ": " + this.pp1, 2, 2, 0);
            g.setColor(0);
            g.drawString(this.nomedele + ": " + this.pp2, 2, 2 + g.getFont().getHeight(),
                    0);
        }
        if (this.play == 2) {
            g.setColor(65360);
            g.drawString(this.meunome + ": " + this.pp2, 2, 2, 0);
            g.setColor(0);
            g.drawString(this.nomedele + ": " + this.pp1, 2, 2 + g.getFont().getHeight(),
                    0);
        }
    }

    private void renderArea() {
        Graphics g = getGraphics();

        g.setColor(16777215);
        g.fillRect(0, 0, 122, this.areay + 120);

        g.setColor(0);

        g.drawLine(2 + this.celulaw, this.areay, 2 + this.celulaw, this.areay + 120);
        g.drawLine(2 + this.celulaw * 2, this.areay, 2 + this.celulaw * 2, this.areay
                + 120);

        g.drawLine(2, this.areay + this.celulah, 122, this.areay + this.celulah);
        g.drawLine(2, this.areay + this.celulah + this.celulah, 122, this.areay
                + this.celulah + this.celulah);

        int xw = g.getFont().stringWidth("X");
        int ow = g.getFont().stringWidth("O");

        for (int i = 0; i < this.campos.length; i++) {
            int s = this.campos[i];

            if (s == 2) {
                g.drawString("O", 2 + (this.celulaw - ow) / 2
                        + getCellX(i) * this.celulaw, this.areay
                        + (this.celulaw - g.getFont().getHeight()) / 2
                        + getCellY(i) * this.celulah, 0);
            }

            if (s == 1) {
                g.drawString("X", 2 + (this.celulaw - xw) / 2
                        + getCellX(i) * this.celulaw, this.areay
                        + (this.celulaw - g.getFont().getHeight()) / 2
                        + getCellY(i) * this.celulah, 0);
            }
        }

        this.lapis.paint(g);

        renderStatus();
    }

    protected void keyPressed(int k) {
        int ac = getGameAction(k);
        if (this.jogada) {
            switch (ac) {
                case UP:
                    this.camposselecionado -= 3;
                    if (this.camposselecionado < 0) {
                        this.camposselecionado += 9;
                    }
                    posLapis();
                    renderArea();
                    flushGraphics();
                    break;
                case DOWN:
                    this.camposselecionado += 3;
                    if (this.camposselecionado > 8) {
                        this.camposselecionado -= 9;
                    }
                    posLapis();
                    renderArea();
                    flushGraphics();
                    break;
                case LEFT:
                    this.camposselecionado -= 1;
                    if (this.camposselecionado < 0) {
                        this.camposselecionado = 8;
                    }
                    posLapis();
                    renderArea();
                    flushGraphics();
                    break;
                case RIGHT:
                    this.camposselecionado += 1;
                    if (this.camposselecionado > 8) {
                        this.camposselecionado = 0;
                    }
                    posLapis();
                    renderArea();
                    flushGraphics();
                    break;
                case 8:
                    if (this.campos[this.camposselecionado] == 0) {
                        mark(this.play == 1 ? 1 : 2, this.camposselecionado);
                        try {
                            this.saida.writeInt(1);
                            this.saida.writeInt(this.camposselecionado);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        this.lapis.setVisible(false);
                        this.jogada = false;
                        renderArea();
                        flushGraphics();
                    }
                    break;
                case 3:
                case 4:
                case 7:
            }
        }
    }

    private boolean checaGanho(int simbolo) {
        if ((this.campos[0] == simbolo) && (((this.campos[1] == simbolo) && (this.campos[2] == simbolo))
                || ((this.campos[4] == simbolo) && (this.campos[8] == simbolo)) || ((this.campos[3] == simbolo) && (this.campos[6] == simbolo)))) {
            return true;
        }

        if ((this.campos[1] == simbolo) && (this.campos[4] == simbolo)
                && (this.campos[7] == simbolo)) {
            return true;
        }

        if ((this.campos[2] == simbolo) && (((this.campos[4] == simbolo) && (this.campos[6] == simbolo)) || ((this.campos[5] == simbolo) && (this.campos[8] == simbolo)))) {
            return true;
        }

        if ((this.campos[3] == simbolo) && (this.campos[4] == simbolo)
                && (this.campos[5] == simbolo)) {
            return true;
        }

        if ((this.campos[6] == simbolo) && (this.campos[7] == simbolo)
                && (this.campos[8] == simbolo)) {
            return true;
        }

        return false;
    }

    private void posLapis() {
        int lx = 2 + (this.celulaw - this.lapis.getWidth()) / 2
                + getCellX(this.camposselecionado) * this.celulaw;
        int ly = this.areay + (this.celulah - this.lapis.getHeight()) / 2
                + getCellY(this.camposselecionado) * this.celulah;

        this.lapis.setPosition(lx, ly);
    }

    private int getCellX(int campo) {
        return campo % 3;
    }

    private int getCellY(int campo) {
        return campo / 3;
    }

    private void stWait() {
        new Thread() {
            public void run() {
                try {
                    while (true) {
                        int k = Game.this.entrada.readInt();
                        if (k == 1) {
                            int mcampo = Game.this.entrada.readInt();
                            Game.this.mark(Game.this.play == 1 ? 2 : 1, mcampo);
                            Game.this.lapis.setVisible(true);
                            Game.this.jogada = true;
                            Game.this.renderArea();
                            Game.this.flushGraphics();
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
                .start();
    }

    private boolean semEspacos() {
        for (int i = 0; i < this.campos.length; i++) {
            if (this.campos[i] == 0) {
                return false;
            }
        }
        return true;
    }

    private void mark(int simbolo, int mcampo) {
        this.campos[mcampo] = simbolo;
        boolean ganha = checaGanho(simbolo);
        boolean semespacos = semEspacos();

        if (checaGanho(simbolo)) {
            for (int i = 0; i < this.campos.length; i++) {
                this.campos[i] = 0;
            }

            if (simbolo == 1) {
                this.pp1 += 1;
            } else {
                this.pp2 += 1;
            }

            renderArea();
            flushGraphics();
        } else if (semespacos) {
            for (int i = 0; i < this.campos.length; i++) {
                this.campos[i] = 0;
            }
            renderArea();
            flushGraphics();
        }
    }

    public void commandAction(Command c, Displayable d) {
        if (c == cmdMarcar) {
            if (this.campos[this.camposselecionado] == 0) {
                mark(this.play == 1 ? 1 : 2, this.camposselecionado);
                try {
                    this.saida.writeInt(1);
                    this.saida.writeInt(this.camposselecionado);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                this.lapis.setVisible(false);
                this.jogada = false;
                renderArea();
                flushGraphics();
            }
        }
    }
}
